/**
 * nothing.js
 * version: v1.0.1
 * author: dengs
 * mail: cbtak@hotmail.com
 * github: https://github.com/cbtak/nothing
 * create date: 2017-6-18
 *
 * 说明：平时积累常用的一些系统对象扩展、功能函数集
 * 在程序入口直接引入即可：
 * import './utils/nothing'
 *
 * 浏览器环境：window.nothing 或 window.$n
 * 小程序环境：wx.nothing 或 wx.$n
 * import方式：import nothing from './utils/nothing'
 *
 * 更新日志：
 * modify date: 【2018-10-13】更新代码风格（去除“;”号、“"”改为“'”、去除未使用的变量等...），以兼容ESlint校验
 * modify date: 【2018-10-15】调整部分语法，以兼容小程序
 */
const $nt = {
	/**
	 * 对象拷贝
	 * 示例：
	 * let a = {name:'this is a'}
	 * let b = _copy()
	 */
	_copy: function(source) {
		let result = source instanceof Array ? [] : {}
		// 日期类型直接返回
		if (source instanceof Date) {
			return source
		}
		for (let key in source) {
			result[key] = source[key] && typeof source[key] === 'object' ? $nt._copy(source[key]) : source[key]
		}
		return result
	},
	/**
	 * 验证是否空值
	 * 示例：
	 * let checkMsg = $nt._isNull(var) ? 'var is null' : 'var not null'
	 * @param {*} val
	 */
	_isNull: function(val) {
		return val === null || val === '' || val === undefined
	},
	/**
	 * 验证是否非空值
	 * 示例：
	 * let checkMsg = _isNotNull(var) ? 'var not null' : 'var is null'
	 * @param {*} val
	 */
	_isNotNull: function(val) {
		return val !== null && val !== '' && val !== undefined
	},
	/**
	 * 空值处理(类oracle nvl2)
	 * 如果val为空，则返回val1，不为空时，则验证val2是否为空，val2不为空时返回val2，否则返回val
	 * 示例：
	 * let val = _ifNull(val, 'val1', 'val2')
	 * @param {*} val
	 * @param {*} val1
	 * @param {*} val2
	 */
	_ifNull: function(val, val1, val2) {
		return $nt._isNull(val) ? val1 : ($nt._isNull(val2) ? val : val2)
	},
	_getWeek: function(day) {
		let week = ''
		switch (day) {
			case 0:
				week = '日'
				break;
			case 1:
				week = '一'
				break;
			case 2:
				week = '二'
				break;
			case 3:
				week = '三'
				break;
			case 4:
				week = '四'
				break;
			case 5:
				week = '五'
				break;
			case 6:
				week = '六'
				break;
			default:
				week = '无'
				break;
		}
		return week
	},
	/**
	 * 数值舍入处理（可指定小数位数和舍入模式）
	 * @param {*} num       要格式化的数值
	 * @param {*} precision 小数保留位数
	 * @param {*} mode      舍入模式：0:Math.round  1:Math.ceil  -1:Math.floor
	 */
	_toFixed: function(num, precision, mode) {
		num = Number(num)
		precision = Number(precision || 0)
		mode = [0, 1, -1]._contains(mode) ? mode : 0
		// 舍入处理
		num = $nt._caseValue(mode,
			0, (precision ? Math.round(num * Math.pow(10, precision)) * (1 / Math.pow(10, precision)) : Math.round(num)),
			1, (precision ? Math.ceil(num * Math.pow(10, precision)) * (1 / Math.pow(10, precision)) : Math.ceil(num)),
			-1, (precision ? Math.floor(num * Math.pow(10, precision)) * (1 / Math.pow(10, precision)) : Math.floor(num))
		)
		return Number(num.toFixed(precision))
	},
	/**
	 * 数值格式化
	 * @param {*} num       要格式化的数值
	 * @param {*} params    参数对象
	 * 参数对象说明：
	 * num              要格式化的数值
	 * params.mode      舍入模式：0:Math.round  1:Math.ceil  -1:Math.floor
	 * params.thousands 是否显示千分位
	 * params.precision 保留小数位数
	 * 示例：
	 * _numberFormat(12806.123)                                                返回：12806
	 * _numberFormat(12806.123, {mode: 0, thousands: true, precision: 2})      返回：12,806.12
	 * _numberFormat(12806.123, {mode: 1, precision: 2})                       返回：12806.13
	 * _numberFormat(12806.126, {mode: -1, thousands: false, precision: 2})    返回：12806.12
	 */
	_numberFormat: function(num, params) {
		if ($nt._isNull(num)) return num
		num = Number(num)
		params = params || {}
		// 舍入模式：0:Math.round  1:Math.ceil  -1:Math.floor
		let mode = [0, 1, -1]._contains(params.mode) ? params.mode : 0
		// 是否显示千分位
		let thousands = $nt._isNull(params.thousands) ? false : params.thousands
		// 显示小数位数
		let precision = $nt._isNull(params.precision) ? 0 : params.precision
		// 舍入处理
		num = $nt._caseValue(mode,
			0, (precision ? Math.round(num * Math.pow(10, precision)) * (1 / Math.pow(10, precision)) : Math.round(num)),
			1, (precision ? Math.ceil(num * Math.pow(10, precision)) * (1 / Math.pow(10, precision)) : Math.ceil(num)),
			-1, (precision ? Math.floor(num * Math.pow(10, precision)) * (1 / Math.pow(10, precision)) : Math.floor(num))
		)
		// 按小数点分割为数组
		let tempArr = num.toString().split('.')
		// 小数点后的数值处理
		tempArr[1] = tempArr[1] || ''
		if (precision) {
			// 截去多余位数
			tempArr[1] = tempArr[1].substr(0, precision)
			// 小数位数处理（不够位数补0）
			tempArr[1] = '.' + tempArr[1] + new Array(precision - tempArr[1].length + 1).join('0')
		}
		// 根据是否显示千分位格式化返回
		// return (thousands ? Number(tempArr[0]).toLocaleString() : tempArr[0]) + (precision ? tempArr[1] : '')
		return (thousands ? Number(tempArr[0]).replace(/(\d)(?=(?:\d{3})+$)/g, '$1,') : tempArr[0]) + (precision ? tempArr[
			1] : '')
	},
	/**
	 * 获取地址栏参数
	 * 示例：
	 * let userid = _getParam('userid')
	 * @param {*} key
	 */
	_getParam: function(key) {
		let reg = new RegExp('(^|&)' + key + '=([^&]*)(&|$)', 'i')
		let r = window.location.search.substr(1).match(reg)
		return r ? unescape(r[2]) : null
	},
	/**
	 * 匹配函数，类似 oracle 中的 decode
	 * 说明：取第一个参数与后续偶数位置的参数进行比较，如匹配则返回当前比较的偶数位置下一个参数作为结果
	 * 如未找到匹配项目，并且参数个数大于3而且为偶数，则取最后一个参数作为默认值返回
	 * 注：参数为动态参数，参数个数最少为3，否则无意义
	 *     偶数位置被比较的参数可以为数组
	 *     比较使用 === 及 indexOf() 严格匹配值
	 * 示例：
	 * 1. _caseValue('A', 'A', value1, 'B', value2) // 返回 value1
	 * 2. _caseValue('A', 'B', value1, 'A', value2) // 返回 value2
	 * 3. _caseValue('A', 'B', value1, 'C', value2, defaultValue) // 返回 defaultValue
	 * 4. _caseValue('A', 'B', value1, ['A','C'], value2, defaultValue) // 返回 value2
	 *
	 * @param {*} args 动态参数
	 */
	_caseValue: function(...args) {
		if (!args || args.length < 3) {
			return null
		}
		let caseKey = args[0]
		for (let i = 1; i < args.length; i++) {
			if ((i % 2) && i !== args.length - 1 && (args[i] === caseKey || (Array.isArray(args[i]) && args[i].indexOf(caseKey) !==
					-1))) {
				return args[i + 1] === undefined ? null : args[i + 1]
			}
		}
		return args.length > 3 && !(args.length % 2) ? args[args.length - 1] : null
	},
	/**
	 * 构建树型数据
	 * @param {*} params
	 */
	_buildTree: function(params) {
		if (!params.treeArray) {
			params.treeArray = []
		}
		if (params.element === null) {
			params.elementArray.forEach(function(item, index, array) {
				if (item[params.parentKey] === params.rootParentValue) {
					params.treeArray[params.treeArray.length] = item
				} else {
					$nt._buildTree({
						element: item,
						elementArray: params.elementArray,
						treeArray: params.treeArray,
						elementKey: params.elementKey,
						parentKey: params.parentKey,
						childKey: params.childKey,
						rootParentValue: params.rootParentValue
					})
				}
			})
		} else {
			params.elementArray.forEach(function(item, index, array) {
				if (params.element[params.parentKey] === item[params.elementKey]) {
					item[params.childKey] = item[params.childKey] || []
					item[params.childKey][item[params.childKey].length] = params.element
					// params.element.parentElement = item
				}
			})
		}
	},
	/**
	 * 验证手机号码
	 * @param {*} mobile
	 */
	_validateMobile: function(mobile) {
		return /^[1][3,4,5,7,8][0-9]{9}$/.test(mobile)
	},
	/**
	 * 数值型验证
	 * @param {*} val
	 */
	_validateNumber: function(val) {
		return /^\d+(\.\d+)?$/.test(val)
	},
	/**
	 * json转成url
	 * @param {*} json
	 */
	_jsonParseUrl: function(json) {
		let tempArr = [];
		for (let i in json) {
			let key = encodeURIComponent(i);
			let value = encodeURIComponent(json[i]);
			tempArr.push(key + '=' + value);
		}
		let urlParamsStr = tempArr.join('&');
		return urlParamsStr;
	},
	/**
	 * 数字转整数 如 100000 转为10万
	 * @param {需要转化的数} num 
	 * @param {需要保留的小数位数} point
	 */
	_tranNumber(num = 0, point = 0) {
		let numStr = num.toString()
		// if (numStr.length < 3) return numStr
		// if (numStr.length == 3) return '99+'
	// if (numStr.length == 4) return '999+'
	if (numStr.length < 5) return numStr
		else if (numStr.length > 8) {
			// 大于8位数是亿
			let decimal = numStr.substr(numStr.length - 8, numStr.length - 8 + point)
			return parseFloat(parseInt(num / 100000000) + '.' + decimal) + '亿'
		} else if (numStr.length >= 5) {
			// 大于6位数是十万 (以10W分割 10W以下全部显示)
			let decimal = numStr.substr(numStr.length - 4, numStr.length - 4 + point)
			return parseFloat(parseInt(num / 10000) + '.' + decimal) + '万'
		}
	},
	/**
	 * 系统对象功能扩展
	 */
	_extend: function() {
		/**
		 * 字符串清除左右空格扩展
		 * 示例：
		 * let str = ' this is string '
		 * let trimStr = str._trim()
		 */
		String.prototype._trim = function() {
			return this.replace(/(^\s*)|(\s*$)/g, '')
		}
		/**
		 * 字符串替换所有
		 * 示例：
		 * let str = ' this is string '
		 * let replaceStr = str.replaceAll('i','')
		 */
		String.prototype.replaceAll = function(s1, s2) {
			return this.replace(new RegExp(s1, 'gm'), s2)
		}
		/**
		 * 字符串包含检查
		 * @param {*} str
		 */
		String.prototype._contains = function(str) {
			return this.indexOf(str) !== -1
		}
		/**
		 * 字符串转byte数组
		 */
		String.prototype._toByte = function() {
			let bytes = []
			let len
			let c
			len = this.length
			for (let i = 0; i < len; i++) {
				c = this.charCodeAt(i)
				if (c >= 0x010000 && c <= 0x10FFFF) {
					bytes.push(((c >> 18) & 0x07) | 0xF0)
					bytes.push(((c >> 12) & 0x3F) | 0x80)
					bytes.push(((c >> 6) & 0x3F) | 0x80)
					bytes.push((c & 0x3F) | 0x80)
				} else if (c >= 0x000800 && c <= 0x00FFFF) {
					bytes.push(((c >> 12) & 0x0F) | 0xE0)
					bytes.push(((c >> 6) & 0x3F) | 0x80)
					bytes.push((c & 0x3F) | 0x80)
				} else if (c >= 0x000080 && c <= 0x0007FF) {
					bytes.push(((c >> 6) & 0x1F) | 0xC0)
					bytes.push((c & 0x3F) | 0x80)
				} else {
					bytes.push(c & 0xFF)
				}
			}
			return bytes
		}
		/**
		 * byte数组转换字符串
		 * @param {*} bytes
		 */
		String._fromByte = function(bytes) {
			if (!Array.isArray(bytes)) return null
			let str = ''
			let _arr = bytes
			for (let i = 0; i < _arr.length; i++) {
				let one = _arr[i].toString(2)
				let v = one.match(/^1+?(?=0)/)
				if (v && one.length === 8) {
					let bytesLength = v[0].length
					let store = _arr[i].toString(2).slice(7 - bytesLength)
					for (let st = 1; st < bytesLength; st++) {
						store += _arr[st + i].toString(2).slice(2)
					}
					str += String.fromCharCode(parseInt(store, 2))
					i += bytesLength - 1
				} else {
					str += String.fromCharCode(_arr[i])
				}
			}
			return str
		}
		/**
		 * Number对象扩展数值格式化
		 * @param {*} params 参数对象
		 *
		 * 参数对象说明：
		 * params.mode      舍入模式：0:Math.round  1:Math.ceil  -1:Math.floor
		 * params.thousands 是否显示千分位
		 * params.precision 保留小数位数
		 * 示例：
		 * Number(12806.123)._format()                                              返回：12806
		 * Number(12806.123)._format({mode: 0, thousands: true, precision: 2})      返回：12,806.12
		 * Number(12806.123)._format({mode: 1, precision: 2})                       返回：12806.13
		 * Number(12806.126)._format({mode: -1, thousands: false, precision: 2})    返回：12806.12
		 */
		Number.prototype._format = function(params) {
			return $nt._numberFormat(this, params)
		}
		/**
		 * 数值舍入处理（可指定小数位数和舍入模式）
		 * @param {*} precision 小数保留位数
		 * @param {*} mode      舍入模式：0:Math.round  1:Math.ceil  -1:Math.floor
		 */
		Number.prototype._toFixed = function(precision, mode) {
			return $nt._toFixed(this, precision, mode)
		}
		/**
		 * 日期格式化
		 * @param {*} fmt 日期格式
		 */
		Date.prototype._format = function(fmt) {
			if (fmt) {
				fmt = fmt.replace('H', 'h').replace('H', 'h')
			}
			let o = {
				'M+': this.getMonth() + 1, // 月份
				'd+': this.getDate(), // 日
				'h+': this.getHours(), // 小时
				'm+': this.getMinutes(), // 分
				's+': this.getSeconds(), // 秒
				'q+': Math.floor((this.getMonth() + 3) / 3), // 季度
				'S': this.getMilliseconds() // 毫秒
			}
			if (/(y+)/.test(fmt)) fmt = fmt.replace(RegExp.$1, (this.getFullYear() + '').substr(4 - RegExp.$1.length))
			for (let k in o) {
				if (new RegExp('(' + k + ')').test(fmt)) fmt = fmt.replace(RegExp.$1, (RegExp.$1.length === 1) ? (o[k]) : (('00' +
					o[k]).substr(('' + o[k]).length)))
			}
			return fmt
		}
		/**
		 * 日期计算
		 * @param {*} interval
		 * @param {*} number
		 */
		Date.prototype._add = function(interval, number) {
			// let cloneDate = JSON.parse(JSON.stringify({date : this}))
			// let d = new Date(cloneDate.date)
			let d = new Date(this)
			let k = {
				'y': 'FullYear',
				'q': 'Month',
				'm': 'Month',
				'w': 'Date',
				'd': 'Date',
				'h': 'Hours',
				'n': 'Minutes',
				's': 'Seconds',
				'ms': 'MilliSeconds'
			}
			let n = {
				'q': 3,
				'w': 7
			}
			interval = (interval || '').toLowerCase()
			d['set' + k[interval]](d['get' + k[interval]]() + ((n[interval] || 1) * number))
			return d
		}
		/**
		 * 日期差异
		 * @param {*} interval
		 * @param {*} objDate2
		 */
		Date.prototype._diff = function(interval, diffDate) {
			let d = this
			let i = {}
			let t = d.getTime()
			let t2 = diffDate.getTime()
			i['y'] = diffDate.getFullYear() - d.getFullYear()
			i['q'] = i['y'] * 4 + Math.floor(diffDate.getMonth() / 4) - Math.floor(d.getMonth() / 4)
			i['m'] = i['y'] * 12 + diffDate.getMonth() - d.getMonth()
			i['ms'] = diffDate.getTime() - d.getTime()
			i['w'] = Math.floor((t2 + 345600000) / (604800000)) - Math.floor((t + 345600000) / (604800000))
			i['d'] = Math.floor(t2 / 86400000) - Math.floor(t / 86400000)
			i['h'] = Math.floor(t2 / 3600000) - Math.floor(t / 3600000)
			i['n'] = Math.floor(t2 / 60000) - Math.floor(t / 60000)
			i['s'] = Math.floor(t2 / 1000) - Math.floor(t / 1000)
			return i[interval]
		}
		/**
		 * 数组为空校验
		 * @param {*} array
		 */
		Array._isEmpty = function(array) {
			return !array || !array.length
		}
		/**
		 * 数组不为空校验
		 * @param {*} array
		 */
		Array._isNotEmpty = function(array) {
			return array && array.length
		}
		/**
		 * 数组对象扩展-为空校验
		 */
		Array.prototype._isEmpty = function() {
			return Array._isEmpty(this)
		}
		/**
		 * 数组对象扩展-不为空校验
		 */
		Array.prototype._isNotEmpty = function() {
			return Array._isNotEmpty(this)
		}
		/**
		 * 数组是否包含元素
		 * @param {*} array
		 * @param {*} element
		 */
		Array._contains = function(array, element) {
			return !array && array.indexOf(element) !== -1
		}
		/**
		 * 数组对象扩展-是否包含元素
		 * @param {*} element
		 */
		Array.prototype._contains = function(element) {
			return this.indexOf(element) !== -1
		}
		/**
		 * 数组对象扩展-添加元素（可指定位置）
		 * @param {*} item  元素
		 * @param {*} index 添加位置(可选，为空时添加到数组末尾)
		 */
		Array.prototype._add = function(item, index) {
			if ($nt._isNotNull(index)) {
				this.splice(index, 0, item)
			} else {
				this.push(item)
			}
		}
		/**
		 * 数组对象扩展-批量添加元素（可指定位置）
		 * @param {*} items  元素数组
		 * @param {*} index 添加位置(可选，为空时添加到数组末尾)
		 */
		Array.prototype._addAll = function(items, index) {
			this.splice($nt._ifNull(index, this.length), 0, ...items)
		}
		/**
		 * 数组对象扩展-添加元素到数据第一个位置
		 * @param {*} item 元素
		 */
		Array.prototype._addFirst = function(item) {
			this._add(item, 0)
		}
		/**
		 * 数组对象扩展-获取数组第一个元素
		 */
		Array.prototype._first = function() {
			return this[0]
		}
		/**
		 * 数组对象扩展-获取数组最后一个元素
		 */
		Array.prototype._last = function() {
			return this[this.length - 1]
		}
		/**
		 * 数组对象扩展-汇总数组元素（数值型有效）
		 * @param {*} beginIndex    开始位置
		 * @param {*} endIndex      结束位置
		 */
		Array.prototype._sum = function(beginIndex, endIndex) {
			let total = 0
			beginIndex = $nt._isNull(beginIndex) ? 0 : beginIndex
			endIndex = $nt._isNull(endIndex) ? this.length : endIndex
			for (let i = 0; i < this.length; i++) {
				if (i >= beginIndex && i < endIndex) {
					total += Number(this[i] || 0)
				}
			}
			return total
		}
		/**
		 * 数组对象扩展-汇总数组元素对象指定属性（数值型有效）
		 * @param {*} attribute     属性
		 * @param {*} beginIndex    开始位置
		 * @param {*} endIndex      结束位置
		 */
		Array.prototype._sumAttr = Array.prototype._sumObjectAttr = function(attribute, beginIndex, endIndex) {
			let total = 0
			beginIndex = $nt._isNull(beginIndex) ? 0 : beginIndex
			endIndex = $nt._isNull(endIndex) ? this.length : endIndex
			for (let i = 0; i < this.length; i++) {
				if (i >= beginIndex && i < endIndex) {
					total += Number(this[i][attribute] || 0)
				}
			}
			return total
		}
		/**
		 * 数组对象扩展-移除元素
		 * @param {*} element
		 */
		// Array.prototype._remove = function (element) {
		//   this.splice(this.findIndex(item => item === element), 1)
		//   return this
		// }
		Object.defineProperty(Array.prototype, '_remove', {
			value: function(element) {
				return this.splice(this.findIndex(item => item === element), 1)
			}
		})
		/**
		 * 数组对象扩展-批量获取属性值
		 * 示例：
		 * let jsonArray = [{a:1,b:1},{a:2,b:2},{a:3,b:3},{a:4,b:4},{a:5,b:5}]
		 * let valueArray = jsonArray._getObjectAttr('a') 或 _getObjectAttr('a')
		 * let valueArray = jsonArray._getObjectAttr('a', 1, 3) 或 _getObjectAttr('a', 1, 3)
		 * @param {*} attribute
		 * @param {*} beginIndex
		 * @param {*} endIndex
		 */
		Array.prototype._getAttr = Array.prototype._getObjectAttr = Array.prototype._getObjectAttribute = function(
			attribute, beginIndex, endIndex) {
			let valArray = []
			beginIndex = $nt._isNull(beginIndex) ? 0 : beginIndex
			endIndex = $nt._isNull(endIndex) ? this.length : endIndex
			for (let i = 0; i < this.length; i++) {
				if (i >= beginIndex && i < endIndex) {
					let val = (typeof this[i][attribute] === 'object' && !(this[i][attribute] instanceof Date) ? $nt._copy(this[i][
						attribute
					]) : this[i][attribute]) || null
					valArray.push(val)
				}
			}
			return valArray
		}
		/**
		 * 数组对象扩展-批量设置属性值
		 * 示例：
		 * let jsonArray = [{a:1,b:1},{a:2,b:2},{a:3,b:3},{a:4,b:4},{a:5,b:5}]
		 * jsonArray._setObjectAttr('c', '10') 或 _setObjectAttribute('c', '10')
		 * jsonArray._setObjectAttr('c', '10', 1, 3) 或 _setObjectAttribute('c', '10', 1, 3)
		 * @param {*} attribute     属性
		 * @param {*} beginIndex    开始位置
		 * @param {*} endIndex      结束位置
		 */
		Array.prototype._setObjectAttr = Array.prototype._setObjectAttribute = function(attribute, value, beginIndex,
			endIndex) {
			beginIndex = $nt._isNull(beginIndex) ? 0 : beginIndex
			endIndex = $nt._isNull(endIndex) ? this.length : endIndex
			for (let i = 0; i < this.length; i++) {
				if (i >= beginIndex && i < endIndex && typeof this[i] === 'object' && !(this[i] instanceof Date)) {
					this[i][attribute] = value
				}
			}
			return this
		}
		/**
		 * 数组对象扩展-批量设置对象本身属性到指定属性
		 * @param {*} sourceAttribute   源属性
		 * @param {*} targetAttribute   目标属性
		 * @param {*} beginIndex        开始位置
		 * @param {*} endIndex          结束位置
		 */
		Array.prototype._setObjectAttrToAttr = Array.prototype._setObjectAttributeToAttribute = function(sourceAttribute,
			targetAttribute, beginIndex, endIndex) {
			beginIndex = $nt._isNull(beginIndex) ? 0 : beginIndex
			endIndex = $nt._isNull(endIndex) ? this.length : endIndex
			for (let i = 0; i < this.length; i++) {
				if (i >= beginIndex && i < endIndex && typeof this[i] === 'object' && !(this[i] instanceof Date)) {
					this[i][targetAttribute] = this[i][sourceAttribute]
				}
			}
			return this
		}
		/**
		 * JSON.__proto__._serializeArray 目前与VUE.JS不兼容，使用 JSON._serializeArray 代替
		 */
		JSON._serializeArray = function(json) {
			let _arr = []
			let _toArray = function(json, jsonArray, prefix) {
				for (let key in json) {
					if (typeof json[key] === 'function') {
						continue
					}
					let newKey = (prefix ? prefix + '.' : '') + key
					if (typeof json[key] === 'object' && !(json[key] instanceof Array)) {
						_toArray(json[key], jsonArray, newKey)
					} else {
						jsonArray[jsonArray.length] = {
							name: newKey,
							value: json[key]
						}
					}
				}
			}
			_toArray(json, _arr)
			return _arr
		}
		/**
		 * JSON.__proto__._propertyLength 目前与VUE.JS不兼容，使用 JSON._propertyLength 代替
		 */
		JSON._propertyLength = function(json) {
			let length = 0
			let keys = []
			for (let key in json) {
				length++
				keys.push(key)
			}
			return length
		}
		/**
		 * 清空JSON对象
		 * @param {*} json
		 */
		JSON._clear = function(json) {
			for (let key in json) {
				delete json[key]
			}
		}
		/**
		 * 移除JSON对象指定属性
		 * @param {*} json
		 * @param {*} key
		 */
		JSON._removeKey = function(json, key) {
			delete json[key]
		}
		/**
		 * 传入JSON数据对象，构建新JSON对象（attrs指定动态属性集）
		 * @param {*} json
		 * @param {*} attrs
		 */
		JSON._new = function(json, ...attrs) {
			let newJSON = {}
			if (json && attrs && attrs.length) {
				let tempJSON = $nt._copy(json)
				for (let i = 0; i < attrs.length; i++) {
					if (attrs[i]._contains('.')) {
						let childAttrs = attrs[i].split('.')
						let childJSON = newJSON[childAttrs[0]] = newJSON[childAttrs[0]] || {}
						let tempChildJSON = tempJSON[childAttrs[0]] || {}
						for (let ii = 1; ii < childAttrs.length; ii++) {
							if (ii === childAttrs.length - 1) {
								childJSON[childAttrs[ii]] = $nt._isNotNull(tempChildJSON) ? tempChildJSON[childAttrs[ii]] : null
							} else {
								childJSON = childJSON[childAttrs[ii]] = childJSON[childAttrs[ii]] || {}
								tempChildJSON = $nt._isNotNull(tempChildJSON) ? tempChildJSON[childAttrs[ii]] : null
							}
						}
					} else {
						newJSON[attrs[i]] = tempJSON[attrs[i]]
					}
				}
			}
			return newJSON
		}
		/**
		 * Storage 对象扩展
		 */
		if (window && window.Storage) {
			/**
			 * 扩展 Storage 增加setJSON方法
			 * @param {*} key
			 * @param {*} value
			 */
			window.Storage.prototype.setJSON = function(key, value) {
				this.setItem(key, $nt._isNotNull(value) ? JSON.stringify(value) : value)
			}
			/**
			 * 扩展 Storage 增加getJSON方法
			 * @param {Object} key
			 */
			window.Storage.prototype.getJSON = function(key) {
				let value = this.getItem(key)
				return $nt._isNotNull(value) ? JSON.parse(value) : null
			}
		}
	}
}
/**
 * 执行系统对象功能扩展
 */
$nt._extend()

if (typeof wx !== 'undefined' && !wx.miniProgram) {
	// 小程序环境
	wx.nothing = wx.$n = $nt
} else {
	window.nothing = window.$n = $nt
	Object.assign(window, $nt)
}

export default $nt
